/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#ifndef __CONVERTERIMPL_H__
#define __CONVERTERIMPL_H__

#define __int64 long long
#pragma warning(disable:4800)

#include <stddef.h>

namespace liba
{

/** This functions, classes and templates are very useful helpers for
	ConverterTraits of simple types and also for ConverterTraits of your 
	own types. */
namespace converter
{
const char * simple_convert(const char * ptr, const char * end, short * value);
const char * simple_convert(const char * ptr, const char * end, int * value);
const char * simple_convert(const char * ptr, const char * end, unsigned * value);
const char * simple_convert(const char * ptr, const char * end, long * value);
const char * simple_convert(const char * ptr, const char * end, unsigned long * value);
const char * simple_convert(const char * ptr, const char * end, __int64 * value);
const char * simple_convert(const char * ptr, const char * end, float * value);
const char * simple_convert(const char * ptr, const char * end, double * value);

const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, short * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, int * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, unsigned * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, long * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, unsigned long * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, __int64 * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, float * value);
const wchar_t * simple_convert(const wchar_t * ptr, const wchar_t * end, double * value);

int simple_print(char * ptr, int value);
int simple_print(char * ptr, unsigned value);
int simple_print(char * ptr, unsigned long value);
int simple_print(char * ptr, __int64 value);
int simple_print(char * ptr, float value);
int simple_print(char * ptr, double value);

int simple_print(wchar_t * ptr, int value);
int simple_print(wchar_t * ptr, unsigned value);
int simple_print(wchar_t * ptr, unsigned long value);
int simple_print(wchar_t * ptr, __int64 value);
int simple_print(wchar_t * ptr, float value);
int simple_print(wchar_t * ptr, double value);

bool simple_convert(const char * ptr, const char * end, wchar_t * buf);
bool simple_convert(const wchar_t * ptr, const wchar_t * end, char * buf);

bool simple_convert(const char * ptr, const char * end, char * buf);
bool simple_convert(const wchar_t * ptr, const wchar_t * end, wchar_t * buf);

	template<class Sym>
	struct ConverterBuffer
	{
		template<class T>
		bool convert(const std::basic_string<T> &value)
		{
			if (value.empty())
			{
				data.clear();
				return true;
			}
            
			std::vector<Sym> buf;
			buf.resize(value.size());
			bool res = liba::converter::simple_convert( value.c_str(), value.c_str() + value.size(), &(buf.front()) );
			// STL strings don't require the last character in the range to be 0
			data.assign( buf.begin(), buf.end() );
			return res;
		}
        
		bool convert(const std::basic_string<Sym> &value)
		{
			data = value;
			return true;
		}
        
		const Sym* begin() const
		{
			return data.c_str();
		}
        
		const Sym* end() const
		{
			return data.c_str() + data.size();
		}
        
	private:
		std::basic_string<Sym> data;
	};

    
    template<class Sym, class Dst>
    struct ConverterTraits< Sym, std::basic_string<Dst> >
    {
        typedef ConverterBuffer<Sym> Buffer;
        
        template<class FromSym>
        static bool convert(const FromSym * be, const FromSym * en, std::basic_string<Dst> * dst)
        {
            ConverterBuffer<typename std::basic_string<Dst>::value_type> buf;
            bool res = buf.convert( std::basic_string<FromSym>( be, en ) );
            if (res)
                dst->assign( buf.begin(), buf.end() );
            return res;
        }
    };
    
/** This template is used as a base for ConverterTraits of types, which string 
	reresentation has limited length. */
template<class Sym, int buf_size>
struct ConverterStaticBuffer
{
	const Sym * begin()const
	{
		return data;
	}
	const Sym * end()const
	{
		return data + size;
	}
protected:
	Sym data[buf_size];
	int size;
};

/** This template is used as a base for ConverterTraits of simple C++ types. */
template<class Sym, class T>
struct ConverterTraitsSimpleType
{
	struct Buffer : public ConverterStaticBuffer<Sym, 56>
	{
		typedef ConverterStaticBuffer<Sym, 56> StaticBuffer;
		
		bool convert(T value)
		{
			return (StaticBuffer::size = simple_print( StaticBuffer::data, (T)value )) != 0;
		}
	};
	template<class FromSym>
	static bool convert(const FromSym * be, const FromSym * en, T * value)
	{
		return simple_convert( be, en, value);
	}
};

template< class Sym >
struct ConverterTraits<Sym, short>
:	public ConverterTraitsSimpleType<Sym, short>
{};
template< class Sym >
struct ConverterTraits<Sym, int>
:	public ConverterTraitsSimpleType<Sym, int>
{};
template< class Sym >
struct ConverterTraits<Sym, unsigned>
:	public ConverterTraitsSimpleType<Sym, unsigned>
{};
template< class Sym >
struct ConverterTraits<Sym, long>
	:	public ConverterTraitsSimpleType<Sym, long>
{};
template< class Sym >
struct ConverterTraits<Sym, unsigned long>
	:	public ConverterTraitsSimpleType<Sym, unsigned long>
{};
template< class Sym >
struct ConverterTraits<Sym, __int64>
	:	public ConverterTraitsSimpleType<Sym, __int64>
{};
template< class Sym >
struct ConverterTraits<Sym, float>
:	public ConverterTraitsSimpleType<Sym, float>
{};
template< class Sym >
struct ConverterTraits<Sym, double>
:	public ConverterTraitsSimpleType<Sym, double>
{};

/** This template is used as a base for ConverterTraits of single characters. */
template<class Sym>
struct ConverterTraitsSingleChar
{
	struct Buffer
	{
		const Sym * begin()const
		{
			return &sym;
		}
		const Sym * end()const
		{
			return &sym + 1;
		}
		bool convert(Sym value)
		{
			sym = value;
			return true;
		}
	protected:
		Sym sym;
	};

	static bool convert(const Sym * be, const Sym * en, Sym * value)
	{
		if( en - be == 0 )
			return false;
		const Sym * ptr = be; // Limitation Check
		*value = *ptr;
		return true;
	}
};

template<class Sym>
struct ConverterTraits<Sym, Sym>
:	public ConverterTraitsSingleChar<Sym>
{};

/** This template is used as a string, that refers to memory, managed by other object. */
template<class Sym>
class Sequence
{
protected:
	const Sym * be;
	const Sym * en;
public:
	typedef Sym value_type;
	typedef Sym char_type;
	Sequence()
	:	be( 0 ),
		en( 0 )
	{}
	Sequence(const Sym * be, const Sym * en)
	:	be( be ),
		en( en )
	{}
	Sequence(const Sym * be)
	:	be( be ),
		en( be )
	{
		while( *en != Sym(0) )
			++en;
	}
	const Sym * begin()const
	{
		return be;
	}
	const Sym * end()const
	{
		return en;
	}
	size_t size()const
	{
		return en - be;
	}
	bool empty()const
	{
		return en == be;
	}
	int compare(const Sym * seq_be, const Sym * seq_en)const
	{
		size_t seq_size = seq_en - seq_be;
		// Could be specialized for speed
		if( size() != seq_size )
			return int(size() - seq_size);

		const Sym * i = be;
		const Sym * i2 = seq_be;
		for( ; i != en; ++i, ++i2 )
			if( *i != *i2 )
				return *i - *i2;
		return 0;
	}
};

template<class Sym>
struct ConverterTraits<Sym, const Sym *>
{
	struct Buffer : public Sequence< Sym >
	{
		bool convert(const Sym * const value)
		{
			Sequence<Sym>::operator=( Sequence<Sym>(value) );
			return true;
		}
	};
};

/** This template is used as a pair of string and value of some type.
	It is very useful for ConverterTraits of enum types. */
template<class Sym, class T>
struct EnumPair
{
	EnumPair( const Sym * name, const T & value )
	:	name( name ),
		value( value )
	{}
	EnumPair(int)
	:	name( 0, 0 )
	{}
	Sequence<Sym> name;
	T value;
};

/** This helper template function is used in the manner of std::make_pair. */
template<class Sym, class T>
EnumPair<Sym,T> MakeEnumPair( const Sym * name, const T & value )
{
	return EnumPair<Sym,T>( name, value );
}

/** This template is used as a base for ConverterTraits of enum types. */
template<class Sym, class T, const EnumPair<Sym,T> * pairs >
class ConverterTraitsEnumBase
{
public:
	struct Buffer
	{
		const Sym * begin()const
		{
			return pairs[index].name.begin();
		}
		const Sym * end()const
		{
			return pairs[index].name.end();
		}
		bool convert(const T & value)
		{
			for( size_t i = 0; pairs[i].name.begin() != pairs[i].name.end(); ++i )
			{
				if( pairs[i].value == value )
				{
					index = i;
					return true;
				}
			}
			return false;
		}
	private:
		size_t index;
	};

	template<class FromSym>
	static bool convert(const FromSym * be, const FromSym * en, T * value)
	{
		for( size_t i = 0; pairs[i].name.begin() != pairs[i].name.end(); ++i )
		{
			if( pairs[i].name.compare( be, en ) == 0 )
			{
				*value = pairs[i].value;
				return true;
			}
		}
		return false;
	}
};

/** This array contains ANSI names, associated with bool type. */
extern EnumPair<char,bool> InternalBoolNames[];
/** This array contains Unicode names, associated with bool type. */
extern EnumPair<wchar_t,bool> InternalBoolWNames[];

template<>
struct ConverterTraits<char,bool>
:	public ConverterTraitsEnumBase<char, bool, InternalBoolNames>
{};
template<>
struct ConverterTraits<wchar_t,bool>
:	public ConverterTraitsEnumBase<wchar_t, bool, InternalBoolWNames>
{};

template<class Sym>
struct CharTraits
{};

template<>
struct CharTraits<char>
{
	static const char ANGULAR_BRACKET_LEFT;
	static const char ANGULAR_BRACKET_RIGHT;
	static const char SLASH;
	static const char BACKSLASH;
	static const char PALKA;
	static const char EQUAL;
	static const char QUOTE;
	static const char APOS;
	static const char QUESTION;
	static const char EXCLAMATION;
	static const char SEMICOLON;
	static const char MINUS;
	static const char PLUS;
	static const char ZERO;
	static const char DOT;
	static const char SPACE;
	static const char TAB;
	static const char COLON;
	static const char ENDL;
	//URODSTVO: CE include headers already declared isspace as macros
	static bool is_space( char v );
	//URODSTVO: CE include headers already declared isdigit as macros
	static bool is_digit( char v );
	static int convert_digit( char v );
	static bool is_e(char s)
	{
		return s == 'e' || s == 'E';
	}
};

template<>
struct CharTraits<wchar_t>
{
	static const wchar_t ANGULAR_BRACKET_LEFT;
	static const wchar_t ANGULAR_BRACKET_RIGHT;
	static const wchar_t SLASH;
	static const wchar_t BACKSLASH;
	static const wchar_t PALKA;
	static const wchar_t EQUAL;
	static const wchar_t QUOTE;
	static const wchar_t APOS;
	static const wchar_t QUESTION;
	static const wchar_t EXCLAMATION;
	static const wchar_t SEMICOLON;
	static const wchar_t MINUS;
	static const wchar_t PLUS;
	static const wchar_t ZERO;
	static const wchar_t DOT;
	static const wchar_t SPACE;
	static const wchar_t TAB;
	static const wchar_t COLON;
	static const wchar_t ENDL;
	//URODSTVO: CE include headers already declared iswspace as macros
	static bool is_space( wchar_t v );
	//URODSTVO: CE include headers already declared iswdigit as macros
	static bool is_digit( wchar_t v );
	static int convert_digit( wchar_t v );
	static bool is_e(wchar_t s)
	{
		return s == L'e' || s == L'E';
	}
};

} // namespace converter
} // namespace liba

using namespace liba;

#endif //__CONVERTERIMPL_H__